package cn.ncu.wechat.util;

import org.apache.commons.codec.digest.DigestUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class WeChatPayUtil {

    public static String generateSignature(Map<String, String> params, String apiKey) {
        // 1. 参数按字典序排序
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);

        // 2. 拼接成字符串
        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            String value = params.get(key);
            if (value != null && !value.isEmpty()) {
                sb.append(key).append("=").append(value).append("&");
            }
        }
        sb.append("key=").append(apiKey);

        // 3. MD5加密并转为大写
        return DigestUtils.md5Hex(sb.toString()).toUpperCase();
    }

    /**
     * 验证微信支付异步通知的签名是否有效
     *
     * @param params 微信支付异步通知的参数（已解析为 Map）
     * @param apiKey 商户 API 密钥
     * @return 签名是否有效
     */
    public static boolean isSignatureValid(Map<String, String> params, String apiKey) {
        // 1. 获取签名
        String receivedSign = params.get("sign");
        if (receivedSign == null || receivedSign.isEmpty()) {
            return false; // 如果没有签名，直接返回 false
        }

        // 2. 移除签名参数（sign），因为签名不参与签名计算
        params.remove("sign");

        // 3. 对参数进行字典序排序
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);

        // 4. 拼接参数字符串
        StringBuilder stringBuilder = new StringBuilder();
        for (String key : keys) {
            String value = params.get(key);
            if (value != null && !value.isEmpty()) {
                stringBuilder.append(key).append("=").append(value).append("&");
            }
        }
        stringBuilder.append("key=").append(apiKey); // 最后拼接 API 密钥

        // 5. 计算签名
        String calculatedSign = md5(stringBuilder.toString()).toUpperCase();

        // 6. 比较接收到的签名和计算出的签名
        return receivedSign.equals(calculatedSign);
    }

    /**
     * 生成 MD5 签名
     *
     * @param input 需要签名的字符串
     * @return MD5 签名字符串
     */
    private static String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(input.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 algorithm not found", e);
        }
    }
}